if(window.my)
  delete my.ToolButton;


//require the template engine (and all required interfaces by the class)
jsx3.require("jsx3.gui.Template","jsx3.gui.Form");

//define the new class
jsx3.lang.Class.defineClass("my.ToolButton",jsx3.gui.Template.Block,[jsx3.gui.Form],function(BUTTON,button) {

  var Event = jsx3.gui.Event;
  var Interactive = jsx3.gui.Interactive;
  var Form = jsx3.gui.Form;
  
  if(jsx3.ide) {
    jsx3.log("about to load catalog");
    jsx3.ide.loadTemplateCatalog("prop", "jsxapp://toolbutton/properties/catalog.xml",toolbutton);
    jsx3.ide.loadTemplateCatalog("event", "jsxapp://toolbutton/events/catalog.xml",toolbutton);
    jsx3.log("loaded catalog");
  }

  
  /**
   * {int} Value for the type field indicating a normal button.
   * @final @jsxobf-final
   */
  BUTTON.TYPE_NORMAL = 0;

  /**
   * {int} Value for the type field indicating a toggle (2-state) button.
   * @final @jsxobf-final
   */
  BUTTON.TYPE_TOGGLE = 1;

  /**
   * {int} Value for the state field indicating that the toggle button is off.
   * @final @jsxobf-final
   */
  BUTTON.STATE_OFF = 0;

  /**
   * {int} Value for the state field indicating that the toggle button is on.
   * @final @jsxobf-final
   */
  BUTTON.STATE_ON = 1;

  /** {String} @private */
  button.jsximage = null;

  /** {String} @private */
  button.jsxoverimage = null;

  /** {String} @private */
  button.jsxdownimage = null;

  /** {String} @private */
  button.jsxonimage = null;

  /** {String} @private */
  button.jsxdisabledimage = null;

  /** {int} @private */
  button.jsxprefetch = jsx3.Boolean.TRUE;

  /** {int} @private */
  button.jsxtype = BUTTON.TYPE_NORMAL;

  /** {int} @private */
  button.jsxstate = BUTTON.STATE_OFF;

  /** {jsx3.gui.HotKey} @private @jsxobf-clobber */
  button._jsxhotkey = null;

  //define the init (main) method
  button.init = function(strName) {
    this.jsxsuper(strName);
  };
  
  BUTTON.DEFAULT_AFFORDANCE = "3 5 3 5";
  button.complex = {};
  button.complex.img = "url(" + jsx3.gui.Block.SPACE + ")";
  button.complex.icon = jsx3.resolveURI("jsxapp://toolbutton/images/undeploy.gif");
  button.complex.bg = "jsxapp://toolbutton/images/bg.jpg";
  button.complex.bgover = "jsxapp://toolbutton/images/bgover.jpg";
  button.complex.bgdown = "jsxapp://toolbutton/images/bgdown.jpg";
  button.complex.bgon = "jsxapp://toolbutton/images/bgon.jpg";
  button.complex.bgf = "jsxapp://toolbutton/images/bgf.jpg";
  button.complex.bgoverf = "jsxapp://toolbutton/images/bgoverf.jpg";
  button.complex.bgdownf = "jsxapp://toolbutton/images/bgdownf.jpg";
  button.complex.bgonf = "jsxapp://toolbutton/images/bgonf.jpg";
  
  //define the VIEW template
  button.getTemplateXML = function() {
    return ['',
      '<transform xmlns="http://gi.tibco.com/transform/" xmlns:u="http://gi.tibco.com/transform/user" version="1.0">',
        '<template onpaint="this._applyState();">',
          '<inlinebox onmouseover="{onmover}" onmousedown="{onmdown}" onmouseout="{onmout}" onmouseup="{onmup}" onclick="{onclick}" onkeypress="{onenter}" onfocus="{onfocus}" onblur="{onblur}" ',
          'index="{$index}" jsxindex="{$jsxindex}" label="{$label}" title="{$tip}" ',
          'style="white-space:nowrap;vertical-align:top;position:{$position};left:{$left};top:{$top};width:{$width};height:{$height};margin:{$margin};display:{$display};visibility:{$visibility};z-index:{$zindex};cursor:{cursor};style-group:{$style-group}">',
              '<inlinebox style="background-image:{complex.img};background-position:0 0;width:{l_width};overflow:hidden;height:100%;vertical-align:top;"/>',
              '<inlinebox style="display:{i_display};background-image:{complex.img};background-position:{bg_offset};height:100%;vertical-align:top;">',
                '<img u:protected="true" style="vertical-align:middle;border:0px;padding:0px;margin:1px 0px 0px 0px;" src="{src}"/>',
              '</inlinebox>',
              '<inlinebox style="display:{t_display};white-space:nowrap;background-image:{complex.img};background-position:{bg_offset};vertical-align:top;text-align:{$textalign}">',
                '<padding>{txt_padding}</padding>',
                '<height>$$parentheight</height>',
                '<width>{t_width}</width>',
                '<text>{$text}</text>',
              '</inlinebox>',
              '<inlinebox style="background-image:{complex.img};background-position:right top;width:{r_width};overflow:hidden;height:100%;vertical-align:top;"/>',
          '</inlinebox>',
        '</template>',
        '<model>',
          '<var id="i_display" triggers="jsxicon">return jsx3.util.strEmpty(this.jsxicon) ? "none" : "";</var>',
          '<var id="t_display" triggers="jsxtext">return jsx3.util.strEmpty(jsx3.util.strTrim(this.jsxtext+"")) ? "none" : "";</var>',
          '<var id="cursor" triggers="jsxenabled">return this._isEnabled() ? "pointer" : "default";</var>',
          '<var id="l_width" triggers="affordance">return this.getAffordance().split(" ")[3];</var>',
          '<var id="r_width" triggers="affordance">return this.getAffordance().split(" ")[1];</var>',
          '<var id="t_width" triggers="affordance jsxwidth jsxicon">return !jsx3.util.strEmpty(this.jsxwidth) ? this.jsxwidth - (parseInt(this.getAffordance().split(" ")[1]) + parseInt(this.getAffordance().split(" ")[3]) + (jsx3.util.strEmpty(this.jsxicon)?0:16)) : null;</var>',
          '<var id="bg_offset" triggers="affordance">return "-" + this.getPaintProfile().l_width + " 0";</var>',
          '<var id="txt_padding" triggers="jsxpadding">return jsx3.util.strEmpty(this.getPadding()) ? this.getAffordance().split(" ")[0] + " 0 0 0" : this.getPadding();</var>',
          '<var id="src" triggers="jsxicon">return this.getIcon(this.complex.icon);</var>',
        '</model>',
      '</transform>',
    ''].join('');
  };
  
  
  button.onfocus = function(objEvent, objGUI) {
    if(this._isEnabled() && this.getFocusStyle()) {
      this._jsxisfocusing = true;
      this.setProperty("complex.img",this._getCurrentImageURL(false, false,true));
    }
  };
  
  button.onblur = function(objEvent, objGUI) {
    delete this._jsxisfocusing;
    if(this._isEnabled())
      this.setProperty("complex.img",this._getCurrentImageURL(!!this.getImage(), false));
  };
  
  button.onmover = function(objEvent, objGUI) {
    if(this._isEnabled())
      this.setProperty("complex.img",this._getCurrentImageURL(true, false,!!this._jsxisfocusing));
  };
  
  button.onmdown = function(objEvent, objGUI) {
    this._jsxisfocusing = true;
    if(this._isEnabled())
      jsx3.sleep(function() { this.setProperty("complex.img",this._getCurrentImageURL(false, true)); },null,this);
  };
  
  button._internal = function(objEvent,objGUI) {
    return objEvent.toElement().parentNode == objGUI || objEvent.toElement().parentNode.parentNode == objGUI;
  };
  
  button.onmout = function(objEvent, objGUI) {
    if(!this._internal(objEvent, objGUI) && this._isEnabled())
      this.setProperty("complex.img",this._getCurrentImageURL(false, false,!!this._jsxisfocusing));
  };
  
  button.onmup = function(objEvent, objGUI) {
    if(this._isEnabled())
      this.setProperty("complex.img",this._getCurrentImageURL(true, false,!!this._jsxisfocusing));
  };
  
  button.onclick = function(objEvent, objGUI) {
    if(this._isEnabled())
      this._onexecute(objEvent,objGUI);
  };
  
  button.onenter = function(objEvent, objGUI) {
    if(this._isEnabled())
      this._onexecute(objEvent,objGUI);
  };
  
  button._onexecute = function(objEvent,objGUI) {
    if (!objEvent.leftButton() && objEvent.isMouseEvent()) return;

    if (this.getType() == BUTTON.TYPE_TOGGLE) {
      var newState = this.getState() == BUTTON.STATE_OFF ? BUTTON.STATE_ON : BUTTON.STATE_OFF;
      var bCancel = this.doEvent(Interactive.TOGGLE, {objEVENT:objEvent, intSTATE:newState});
      if (bCancel !== false) {
        this.setState(newState);
      }
    }
    this.doEvent(Interactive.EXECUTE, {objEVENT:objEvent});
  };

 
  
  /** @private @jsxobf-clobber */
  button._getCurrentImageURL = function(bOver, bDown, bFocus) {
    var strPath = null;

    if (this.getEnabled() == Form.STATEENABLED) {
      if (bOver)
        strPath = this.getOverImage(bFocus);
      else if (bDown)
        strPath = this.getDownImage(bFocus);

      if (this.getType() == BUTTON.TYPE_TOGGLE && this.getState() == BUTTON.STATE_ON)
        strPath = strPath || this.getOnImage();
    }

    strPath = strPath || this.getImage(bFocus);

    return "url(" + (strPath ? this.getUriResolver().resolveURI(strPath) : "") + ")";
  };


  /**
   * Returns the padding required by the intance to grant adequate room for edges and buffers.
   * @return {String} 
   * @since 3.7
   */
  button.getAffordance = function() {
    return this.affordance || BUTTON.DEFAULT_AFFORDANCE;
  };
  
  /**
   * Sets the padding required by the intance to grant adequate room for the edges and buffers required by the background image.
   * @param strAffordance{String} For example, "2 8 2 8"
   * @since 3.7
   */
  button.setAffordance = function(strAffordance) {
    this.setProperty("affordance",strAffordance);
  };
  
  //subclass of method in jsx3.gui.Form to ensure the icon gets greyed out
  button.setEnabled = function(intEnabled) {
    this.setProperty("jsxenabled",intEnabled);
    this._applyState();
  };
  
  
  //called when the button state is toggled or when the button is painted on-screen
  //provides a valid x-browser approach for setting opacity
  button._applyState = function()  {
    this._jsxisfocusing = false;
    this._setKeyBinding();
    this.setProperty("complex.img",this._getCurrentImageURL(false, false));
    //this.setProperty("complex.img","url(" + (this.getBGPersist() ? this.getOverImage(this.complex.bgover) : jsx3.gui.Block.SPACE) + ")");

    if(!this._isEnabled())
      jsx3.html.DOM.setStyles(this.getRendered(),jsx3.html.getCSSOpacity(.5));
    else
      jsx3.html.DOM.setStyles(this.getRendered(),jsx3.html.getCSSOpacity(1));
  };
  
  
  //called when the control is painted
  button._setKeyBinding = function() {
    var myKeyBinding = this.getKeyBinding();
    if (myKeyBinding) {
      var me = this;
      if (this._jsxhotkey != null)
        this._jsxhotkey.destroy();
      this._jsxhotkey = this.doKeyBinding(function(e){ me._ebClick(e, me.getRendered()); }, myKeyBinding);
      if (this._jsxhotkey) this._jsxhotkey.setEnabled(bEnabled);
    }
  };
  
  //convenience method to check disabled state
  button._isEnabled = function() {
    return this.getEnabled() == null || this.getEnabled();
  };
  
  /**
   * Returns the URL to use for the 16x16 icon. 
   * @param-private strDefault {String}
   * @return {String}
   * @since 3.7
   */
  button.getIcon = function(strDefault) {
    return !jsx3.util.strEmpty(this.jsxicon) ? this.getServer().resolveURI(this.jsxicon) : strDefault;
  };
  
  /**
   * Sets the URL to use for the dropdown image (16x16).
   * @param strPath {String} This URL will be resolved relative to the project path.
   * @since 3.7
   */
  button.setIcon = function(strPath) {
    this.setProperty("jsxicon",strPath);
    this.repaint();
  };


  button.setText = function(strText) {
    this.setProperty("jsxtext",strText);
    this.repaint();
  };


  /**
   * Returns the URL for the background image to use when the control is moused over. If not provided, a default system image will be used.
   * @param-private bFocus {Boolean}
   * @return {String}
   * @since 3.7
   */
  button.getOverImage = function(bFocus) {
    if(bFocus && this.getFocusStyle())
      return this.complex.bgoverf;
    else
      return Number(this.jsxoverimage) == 1 ? this.complex.bgover : (!jsx3.util.strEmpty(this.jsxoverimage) ? this.jsxoverimage : null);
  };
  
  /**
   * Sets the URL for the image to use when the control is moused over.
   * @param strPath {String} This URL will be resolved relative to the project path.
   * @since 3.7
   */
  button.setOverImage = function(strPath) {
    this.jsxoverimage = strPath;
  };

  /**
   * Returns the URL for the background image to use when the control is moused down. If not provided, a default system image will be used.
   * @param-private bFocus {Boolean}
   * @return {String}
   * @since 3.7
   */
  button.getDownImage = function(bFocus) {
    if(bFocus && this.getFocusStyle())
      return this.complex.bgdownf;
    else
      return Number(this.jsxdownimage) == 1 ? this.complex.bgdown : (!jsx3.util.strEmpty(this.jsxdownimage) ? this.jsxdownimage : null);
  };
  
  /**
   * Sets the URL for the image to use when the control is moused down.
   * @param strPath {String} This URL will be resolved relative to the project path.
   * @since 3.7
   */
  button.setDownImage = function(strPath) {
    this.jsxdownimage = strPath;
  };
  

  /**
   * Returns the URI of the image of this image button.
   * @param-private bFocus {Boolean}
   * @return {String}
   */
  button.getImage = function(bFocus) {
    if(bFocus && this.getFocusStyle())
      return this.complex.bgf;
    else
      return Number(this.jsximage) == 1 ? this.complex.bg : (!jsx3.util.strEmpty(this.jsximage) ? this.jsximage : null);
  };

  /**
   * Sets the URI of the image of this image button. This is the default image that is displayed if the button
   * is off or if the button is in a state for which no image URI is specified.
   * @param strImage {String}
   * @return {jsx3.gui.button} this object
   */
  button.setImage = function(strImage) { this.jsximage = strImage; return this; };


  /**
   * Returns the URI of the on image of this image button.
   * @return {String}
   */
  button.getOnImage = function() {
    return Number(this.jsxonimage) == 1 ? this.complex.bgon : (!jsx3.util.strEmpty(this.jsxonimage) ? this.jsxonimage : null);
  };

  /**
   * Sets the URI of the on image of this image button. This is the image that is displayed when this image button is
   * of type <code>TYPE_TOGGLE</code> and its state is <code>STATE_ON</code>.
   * @param strImage {String}
   * @return {jsx3.gui.button} this object
   */
  button.setOnImage = function(strImage) {
    this.jsxonimage = strImage; return this;
  };

  /**
   * Returns the current state of this image button.
   * @return {int} <code>STATE_OFF</code> or <code>STATE_ON</code>
   * @see #STATE_OFF
   * @see #STATE_ON
   */
  button.getState = function() { return this.jsxstate; };


  /**
   * Sets the current state of this image button and updates the displayed image accordingly.
   * @param intState {int} <code>STATE_OFF</code> or <code>STATE_ON</code>
   * @return {jsx3.gui.button} this object
   */
  button.setState = function(intState) {
    this.jsxstate = intState;
    this.setProperty("complex.img",this._getCurrentImageURL(false, !!intState));
    if(intState && !jsx3.util.strEmpty(this.getGroupName()))
      this._deselectSiblings();
  };

  /**
   * If any siblings belong to the same group, make sur their stat is toggled off
   */
  button._deselectSiblings = function() {
    var objSibs = this.getParent().getChildren();
    for(var i=0;i<objSibs.length;i++) {
      objSib = objSibs[i];
      if(objSib != this && objSib.getClass() == this.getClass()  && objSib.getGroupName() == this.getGroupName())
        objSib.setState(0);
    }
  };

  /**
   * Returns the type of this image button.
   * @return {int} <code>TYPE_NORMAL</code> or <code>TYPE_TOGGLE</code>
   * @see #TYPE_NORMAL
   * @see #TYPE_TOGGLE
   */
  button.getType = function() { return this.jsxtype; };

  /**
   * Sets the type of this image button.
   * @param intType {int} <code>TYPE_NORMAL</code> or <code>TYPE_TOGGLE</code>
   * @return {jsx3.gui.button} this object
   */
  button.setType = function(intType) { this.jsxtype = intType; return this; };

  button.setEnabled = function(intEnabled, bRepaint) {
    if (this._jsxhotkey != null)
      this._jsxhotkey.setEnabled(intEnabled == Form.STATEENABLED);
    return this.jsxsupermix(intEnabled, bRepaint);
  };
  

  
  /**
   * If this image button is of type <code>TYPE_TOGGLE</code>, then the state must be either <code>STATE_ON</code>
   * or required must be <code>OPTIONAL</code> to pass validation.
   * @return {int}
   */
  button.doValidate = function() {
    var state = null;

    if (this.getType() == BUTTON.NORMAL)
      state = Form.STATEVALID;
    else
      state = this.getState() == BUTTON.STATE_ON || this.getRequired() == Form.OPTIONAL ?
          Form.STATEVALID : Form.STATEINVALID;

    this.setValidationState(state);
    return state;
  };

  button.emGetType = function() {
    return jsx3.gui.Matrix.EditMask.FORMAT;
  };

  button.emInit = function(objColumn) {
    this.jsxsupermix(objColumn);
  };

  button.emSetValue = function(strValue) {
  };

  button.emGetValue = function() {
    return null;
  };

  button.emBeginEdit = function(strValue, objTdDim, objPaneDim, objMatrix, objColumn, strRecordId, objTD) {
    var toFocus = objTD.childNodes[0].childNodes[0];
    if (toFocus) {
      this.jsxsupermix(strValue, objTdDim, objPaneDim, objMatrix, objColumn, strRecordId, objTD);
      jsx3.html.focus(toFocus);
    } else {
      return false;
    }
  };

  button.emPaintTemplate = function() {
    this.setEnabled(Form.STATEDISABLED);
    var disabled = this.paint();
    this.setEnabled(Form.STATEENABLED); // need to have it enabled afterwards
    var enabled = this.paint();
    return this._emPaintStandardCdfTemplate(enabled, disabled);
  };
  

  /**
   * Sets whether or not the button will display a graphical treatment when it has focus
   * @param intFocus {int} 0 or 1. If 1, the button will implement a focus style
   */
  button.setFocusStyle = function(intFocus) {
    this.focusstyle = intFocus;
  };

  /**
   * Returns whether or not the button will display a graphical treatment when it has focus
   * @return {int}
   */
  button.getFocusStyle = function() {
    return this.focusstyle;
  };

  /**
   * Sets the name of the group (e.g., radio group) that this button (a toggle-type button) belongs to
   * @param strName {String}
   */
  button.setGroupName = function(strName) {
    this.jsxgroupname = strName;
  };

  /**
   * Returns the name of the group (e.g., radio group) that this button (a toggle-type button) belongs to
   * @return {String}
   */
  button.getGroupName = function() {
    return this.jsxgroupname;
  };




});